package com.funo.wcity.app.dao;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.Assert;

import com.funo.wcity.app.utils.Reflections;
import com.funo.wcity.app.utils.StringUtil;

/**
 * 
 * @author 李刚
 *
 */
public class DefaultBaseDao<T,  PK extends Serializable> {
	private Log log = LogFactory.getLog(DefaultBaseDao.class);
	@Resource(name = "jdbcTemplate")
	protected JdbcTemplate jdbcTemplate;
	@Resource(name = "hibernateTemplate")
	protected HibernateTemplate hibernateTemplate;
	private Class<T> entityClass;
	/**
	 * 通过反射获取子类确定的泛型类
	 */
	public DefaultBaseDao() {
		entityClass = Reflections.getSuperClassGenricType(getClass());
	}
	/**
	 * 用于用于省略Dao层, 在Service层直接使用通用的BaseDao构造函数.
	 * 在构造函数中定义对象类型Class.
	 * eg.
	 * BaseDao<User, Long> userDao = new BaseDao<User, Long>(User.class);
	 */
	public DefaultBaseDao(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	/**
	 * @param pageNo
	 * @param pageSize
	 * @param sql
	 * @return
	 * @Adder by zhys 2011-8-12 下午05:00:31
	 * @Description jdbcTemplate 分页语句
	 */
	public Page getPageBySQL(Integer pageNo, Integer pageSize, String sql) {
		// 构造分页查询语句
		pageSize = pageSize == null ? 10 : pageSize;
		pageNo=pageNo==null ||pageNo<1?1:pageNo;
		StringBuffer paginationSQL = new StringBuffer(sql);
		paginationSQL.append(" limit");
		paginationSQL.append(" "+(pageNo-1)*pageSize);
		paginationSQL.append(" ,").append(pageSize);
		int totalCount = getCount(sql.toString());
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		log.info(paginationSQL.toString());
		Page page = new Page(startIndex, totalCount, pageSize,
				this.jdbcTemplate.queryForList(paginationSQL.toString()));
		return page;
	}

	public Page getPageBySQL(Integer pageNo, Integer pageSize, String sql,
			Object[] objs) {
		// 构造分页查询语句
		pageSize = pageSize == null ? 10 : pageSize;
		StringBuffer paginationSQL = new StringBuffer(sql);
		paginationSQL.append(" limit");
		paginationSQL.append(" "+pageNo);
		paginationSQL.append(" ,").append(pageSize);
		int totalCount = getCount(sql.toString(), objs);
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		log.info(paginationSQL.toString());
		Page page = new Page(startIndex, totalCount, pageSize,
				this.jdbcTemplate.queryForList(paginationSQL.toString(), objs));
		return page;
	}

	/**
	 * @param sql
	 * @return
	 * @Adder by zhys 2011-8-13 上午11:47:20
	 * @Description 统计SQL查询回来的条数
	 */
	public int getCount(String sql) {
		String coutSQL = " select count(*)  from ("
				+ sql+") t";
		log.info(coutSQL);
		return this.jdbcTemplate.queryForInt(coutSQL);
	}

	public int getCount(String sql, Object[] orgs) {
		String coutSQL = " select count(*) "
				+ SQLUtils.removeSelect(SQLUtils.removeOrders(sql));
		log.info(coutSQL);
		return this.jdbcTemplate.queryForInt(coutSQL, orgs);
	}

	/**
	 * @param pageNo
	 *            当天页码
	 * @param paginationType
	 *            1全文 2余下全文 其他分页
	 * @param resultMap
	 * @param content
	 *            对哪个字段分页
	 * @return
	 * @Adder by zhys 2011-9-5 上午02:48:57
	 * @Description
	 * 
	 */
	@SuppressWarnings("unchecked")
	public Map<String, Object> paginationClob(Integer pageNo,
			Integer paginationType, Map resultMap, String content) {
		String strContent = (String) resultMap.get(content);
		if (StringUtil.isEmpty(strContent)) {
			resultMap.put("currentPageNo", 0);
			resultMap.put("totalCount", 0);
		} else {
			String[] totalContent = strContent.split("\\[NextPage\\]");
			int totalCount = totalContent.length;
			if (paginationType == 1 || totalCount == 1) {// 全文 和 没有分页符
				strContent = strContent.replace("[NextPage]", "");
				resultMap.put("currentPageNo", 1);
				resultMap.put("totalCount", totalCount);
				resultMap.put(content, strContent);
				resultMap.put("paginationType", 1);
			} else {
				if (pageNo == 0)
					pageNo = 1;
				if (1 <= pageNo && pageNo <= totalCount) {
					if (paginationType == 2 && pageNo < totalCount) {// 余下全文
						strContent = "";// 先清空容器
						for (int a = 0; a < totalCount - pageNo; a++) {
							strContent += totalContent[pageNo + a];
						}
						resultMap.put("paginationType", 2);
						resultMap.put("currentPageNo", 0);
					} else {// 分页查询
						strContent = totalContent[pageNo - 1];
						resultMap.put("paginationType", 0);
						resultMap.put("currentPageNo", pageNo);
					}
					resultMap.put("totalCount", totalCount);
					resultMap.put(content, strContent);
				} else {
					strContent = strContent.replace("[NextPage]", "");
					resultMap.put("currentPageNo", 1);
					resultMap.put("totalCount", totalCount);
					resultMap.put(content, strContent);
					resultMap.put("paginationType", 1);
				}
			}
		}
		return resultMap;
	}
	/**
	 * 根据ID加载PO实例, 如果二级缓存中存在, 则读取二级缓存的数据
	 * 
	 * @param id
	 * @return 返回相应的持久化PO实例
	 */
	public T load(PK id) {
		Assert.notNull(id);
		
		if(log.isDebugEnabled()){
			log.debug("load entity id[" + id + "], entityClass[" + entityClass + "]");
		}
		return (T) hibernateTemplate.load(entityClass, id);
	}

	/**
	 * 根据ID获取PO实例, 如果一级缓存不存在, 则从数据库中读取
	 * 
	 * @param id
	 * @return 返回相应的持久化PO实例
	 */
	public T get(PK id) {
		Assert.notNull(id);
		
		if(log.isDebugEnabled()){
			log.debug("get entity id[" + id + "], entityClass[" + entityClass + "]");
		}
		T t =(T) hibernateTemplate.get(entityClass, id);
		
		return t;
	}

	/**
	 * 获取PO的所有对象
	 * 
	 * @return
	 */
	public List<T> loadAll() {
		
		List<T> lst = hibernateTemplate.loadAll(entityClass);
		
		if(log.isDebugEnabled()){
			log.debug("load all entities[" + entityClass + "]...");
		}
		return lst;
	}
	
	/**
	 * 保存PO
	 * 
	 * @param entity
	 */
	public Serializable save(T entity) {
		Assert.notNull(entity);
		
		if(log.isDebugEnabled()){
			log.debug("save entity[" + entity.toString() + "], entityClass[" + entityClass + "]," +
					" information[" + ToStringBuilder.reflectionToString(entity) + "]");
		}
		return hibernateTemplate.save(entity);
	}

	/**
	 * 删除PO
	 * 
	 * @param entity
	 */
	public void delete(T entity) {
		Assert.notNull(entity);
		
		if(log.isDebugEnabled()){
			log.debug("delete entity[" + entity.toString() + "], entityClass[" + entityClass + "], " +
					"information[" + ToStringBuilder.reflectionToString(entity) + "]");
		}
		hibernateTemplate.delete(entity);
	}

	/**
	 * 更新PO
	 * 
	 * @param entity
	 */
	public void update(T entity) {
		Assert.notNull(entity);
		
		if(log.isDebugEnabled()){
			log.debug("update entity[" + entity.toString() + "], entityClass[" + entityClass + "]," +
					" information[" + ToStringBuilder.reflectionToString(entity) + "]");
		}
		hibernateTemplate.update(entity);
	}
	
	/**
	 * 保存或更新PO
	 * 
	 * @param entity
	 */
	public void saveOrUpdate(T entity) {
		Assert.notNull(entity);
		
		if(log.isDebugEnabled()){
			log.debug("saveOrUpdate entity[" + entity.toString() + "], entityClass[" + entityClass + "], " +
					"information[" + ToStringBuilder.reflectionToString(entity) + "]");
		}
		hibernateTemplate.saveOrUpdate(entity);
	}
	
	/**
	 * 
	 * @param entity
	 */
	public void merge(T entity) {
		Assert.notNull(entity);
		
		if(log.isDebugEnabled()){
			log.debug("merge entity[" + entity.toString() + "], entityClass[" + entityClass + "], " +
					"information[" + ToStringBuilder.reflectionToString(entity) + "]");
		}
		hibernateTemplate.merge(entity);
	}
}
